package com.gzc.just.play.last.war.sceneserver.gameobject.unit;

import com.gzc.just.play.last.war.sceneserver.gameobject.base.GameObjectCamp;
import com.gzc.just.play.last.war.sceneserver.gameobject.base.GameObjectType;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.*;

/**
 * NPC类的单元测试
 * 
 * @author AI Assistant
 * @version 1.0.0
 * @since 2025-11-25
 */
@ExtendWith(MockitoExtension.class)
@DisplayName("NPC类测试")
class NPCTest {

    private TestNPC npc;
    
    @BeforeEach
    void setUp() {
        npc = new TestNPC(
            54321L,              // objectId
            100,                 // npcTypeId
            "Test Monster",      // npcName
            GameObjectCamp.MONSTER, // camp
            800,                 // maxHealth
            200,                 // maxMana
            60.0,                // attack
            30.0,                // defense
            40.0                 // speed
        );
    }
    
    @Test
    @DisplayName("测试NPC创建和基本属性")
    void testNPCCreation() {
        // 验证基本属性
        assertEquals(54321L, npc.getObjectId());
        assertEquals(100, npc.getNpcTypeId());
        assertEquals("Test Monster", npc.getNpcName());
        assertEquals(GameObjectType.NPC, npc.getObjectType());
        assertEquals(GameObjectCamp.MONSTER, npc.getCamp());
        
        // 验证初始AI状态
        assertFalse(npc.isHasAI());
        assertEquals(0, npc.getAiState());
        
        // 验证掉落设置
        assertEquals(0, npc.getDropGoldMin());
        assertEquals(0, npc.getDropGoldMax());
        assertEquals(0, npc.getDropExpMin());
        assertEquals(0, npc.getDropExpMax());
        
        // 验证基础属性
        assertEquals(800, npc.getMaxHealth());
        assertEquals(800, npc.getCurrentHealth());
        assertEquals(200, npc.getMaxMana());
        assertEquals(200, npc.getCurrentMana());
        assertEquals(60.0, npc.getAttack(), 0.001);
        assertEquals(30.0, npc.getDefense(), 0.001);
        assertEquals(40.0, npc.getSpeed(), 0.001);
    }
    
    @Test
    @DisplayName("测试NPC初始化")
    void testNPCInitialization() {
        npc.initialize();
        assertTrue(npc.isActive());
        assertTrue(npc.isAlive());
        assertFalse(npc.isDead());
    }
    
    @Test
    @DisplayName("测试NPC销毁")
    void testNPCDestroy() {
        npc.initialize();
        npc.destroy();
        
        assertFalse(npc.isActive());
        assertFalse(npc.isAlive());
        assertTrue(npc.isDead());
    }
    
    @Test
    @DisplayName("测试AI状态管理")
    void testAIStateManagement() {
        // 默认没有AI
        assertFalse(npc.isHasAI());
        
        // 启用AI
        npc.enableAI();
        assertTrue(npc.isHasAI());
        
        // 禁用AI
        npc.disableAI();
        assertFalse(npc.isHasAI());
        
        // 设置AI状态
        npc.setAiState(5);
        assertEquals(5, npc.getAiState());
    }
    
    @Test
    @DisplayName("测试掉落金币设置")
    void testDropGoldSettings() {
        // 设置掉落范围
        npc.setDropGoldRange(10, 50);
        assertEquals(10, npc.getDropGoldMin());
        assertEquals(50, npc.getDropGoldMax());
        
        // 测试范围修正（确保max >= min）
        npc.setDropGoldRange(100, 50);
        assertEquals(100, npc.getDropGoldMin());
        assertEquals(100, npc.getDropGoldMax());
        
        // 测试获取掉落金币（设置为10-50范围）
        npc.setDropGoldRange(10, 50);
        for (int i = 0; i < 100; i++) {
            int gold = npc.getDropGold();
            assertTrue(gold >= 10 && gold <= 50);
        }
        
        // 测试固定掉落（min == max）
        npc.setDropGoldRange(25, 25);
        assertEquals(25, npc.getDropGold());
    }
    
    @Test
    @DisplayName("测试掉落经验设置")
    void testDropExpSettings() {
        // 设置掉落范围
        npc.setDropExpRange(20, 80);
        assertEquals(20, npc.getDropExpMin());
        assertEquals(80, npc.getDropExpMax());
        
        // 测试范围修正（确保max >= min）
        npc.setDropExpRange(200, 100);
        assertEquals(200, npc.getDropExpMin());
        assertEquals(200, npc.getDropExpMax());
        
        // 测试获取掉落经验（设置为20-80范围）
        npc.setDropExpRange(20, 80);
        for (int i = 0; i < 100; i++) {
            int exp = npc.getDropExp();
            assertTrue(exp >= 20 && exp <= 80);
        }
        
        // 测试固定掉落（min == max）
        npc.setDropExpRange(40, 40);
        assertEquals(40, npc.getDropExp());
    }
    
    @Test
    @DisplayName("测试AI处理")
    void testAIProcessing() {
        npc.initialize();
        npc.enableAI();
        
        long currentTime = System.currentTimeMillis();
        long deltaTime = 100;
        
        // 处理心跳，应该触发AI处理
        npc.processHeartbeat(currentTime, deltaTime);
        
        // 验证AI处理被调用
        assertTrue(npc.isAIProcessed());
    }
    
    @Test
    @DisplayName("测试死亡处理")
    void testDeathHandling() {
        npc.initialize();
        
        // 初始化前NPC应该存活
        assertTrue(npc.isAlive());
        assertFalse(npc.isDead());
        
        // 造成伤害导致死亡
        npc.takeDamage(1000); // 超过最大生命值
        assertTrue(npc.isDead());
        assertEquals(0, npc.getCurrentHealth());
    }
    
    @Test
    @DisplayName("测试NPC特有方法")
    void testNPCSpecificMethods() {
        npc.initialize();
        
        // isHero应该返回false
        assertFalse(npc.isHero());
        
        // isNPC应该返回true
        assertTrue(npc.isNPC());
    }
    
    @Test
    @DisplayName("测试NPC心跳处理")
    void testNPCHeartbeat() {
        npc.initialize();
        
        long currentTime = System.currentTimeMillis();
        long deltaTime = 100;
        
        // 正常情况下的心跳处理
        npc.processHeartbeat(currentTime, deltaTime);
        assertTrue(npc.isActive());
        
        // 死亡后的心跳处理
        npc.die();
        npc.processHeartbeat(currentTime + 100, deltaTime);
        
        // 死亡状态下心跳不会处理
        assertTrue(npc.isDead());
    }
    
    @Test
    @DisplayName("测试NPC toString方法")
    void testNPCToString() {
        String npcString = npc.toString();
        
        // 验证字符串包含关键信息
        assertTrue(npcString.contains("id=54321"));
        assertTrue(npcString.contains("npcId=100"));
        assertTrue(npcString.contains("npcName=Test Monster"));
        assertTrue(npcString.contains("camp=MONSTER"));
        assertTrue(npcString.contains("hp=800/800"));
        assertTrue(npcString.contains("hasAI=false"));
        assertTrue(npcString.contains("alive=true"));
        
        // 启用AI后再测试
        npc.enableAI();
        npcString = npc.toString();
        assertTrue(npcString.contains("hasAI=true"));
    }
    
    @Test
    @DisplayName("测试AI逻辑处理")
    void testAILogicProcessing() {
        npc.initialize();
        
        // 禁用AI时，isHasAI应该返回false
        npc.disableAI();
        assertFalse(npc.isHasAI());
        
        // 启用AI时，isHasAI应该返回true
        npc.enableAI();
        assertTrue(npc.isHasAI());
        
        // 处理心跳不应抛出异常
        long currentTime = System.currentTimeMillis();
        long deltaTime = 500; // 0.5秒
        assertDoesNotThrow(() -> npc.processHeartbeat(currentTime, deltaTime));
    }
    
    @Test
    @DisplayName("测试NPC复杂场景")
    void testComplexNPCScenarios() {
        npc.initialize();
        npc.enableAI();
        
        // 设置掉落
        npc.setDropGoldRange(50, 150);
        npc.setDropExpRange(30, 100);
        
        // 处理一次心跳
        long currentTime = System.currentTimeMillis();
        npc.processHeartbeat(currentTime, 1000);
        
        // 验证状态
        assertTrue(npc.isActive());
        assertTrue(npc.isHasAI());
        
        // 死亡并验证
        npc.die();
        assertTrue(npc.isDead());
        
        // 验证掉落值在正确范围内
        int droppedGold = npc.getDropGold();
        int droppedExp = npc.getDropExp();
        assertTrue(droppedGold >= 50 && droppedGold <= 150);
        assertTrue(droppedExp >= 30 && droppedExp <= 100);
    }
    
    /**
     * 测试用的NPC具体实现类
     */
    private static class TestNPC extends NPC {
        private boolean aiProcessed = false;
        private boolean deathProcessed = false;
        private int droppedGold = 0;
        private int droppedExp = 0;
        
        public TestNPC(long objectId, int npcTypeId, String npcName, GameObjectCamp camp,
                       int maxHealth, int maxMana, double attack, double defense, double speed) {
            super(objectId, npcTypeId, npcName, camp, maxHealth, maxMana, attack, defense, speed);
        }
        
        @Override
        protected void processAI(long currentTime, long deltaTime) {
            aiProcessed = true;
            // 模拟AI处理逻辑
            if (Math.random() < 0.3) {
                setAiState((getAiState() + 1) % 5);
            }
        }
        
        @Override
        protected void onDeath() {
            deathProcessed = true;
            // 记录掉落
            droppedGold = getDropGold();
            droppedExp = getDropExp();
            super.onDeath(); // 调用父类方法
        }
        
        // 测试辅助方法
        public boolean isAIProcessed() {
            return aiProcessed;
        }
        
        public boolean isDeathProcessed() {
            return deathProcessed;
        }
        
        public int getDroppedGold() {
            return droppedGold;
        }
        
        public int getDroppedExp() {
            return droppedExp;
        }
        
        public void resetTestState() {
            aiProcessed = false;
            deathProcessed = false;
            droppedGold = 0;
            droppedExp = 0;
        }
    }
}